namespace Wilco.CodeHilighter.Engine.SyntaxHighlighting
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Text;
    using System.Web;
    using System.Xml;

    /// <summary>
    /// Represents an Html parser.
    /// </summary>
    public class HtmlParser : ParserBase
    {
        #region Fields

        const string lineContentCss = " style=\"float:left;\"";
        const string lineNumberCss = " style=\"float:left;border-right: 1px solid #000;\"";

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of a <see cref="Wilco.CodeHilighter.Engine.SyntaxHighlighting.HtmlParser"/> class.
        /// </summary>
        public HtmlParser()
        {
            //
        }

        #endregion Constructors

        #region Methods

        public string CreateLineNumbering(string html)
        {
            return CreateLineNumbering(html, false);
        }

        public string CreateLineNumbering(string html, bool inlineCss)
        {
            string[] lines = html.Replace("\r", String.Empty).Split('\n');
            List<string> l = new List<string>(lines.Length);
            for (int i = 0; i < lines.Length; i++)
            {
                int lineNumber = (i + 1);
                string line = lines[i];
                l.Add(string.Format("<span class=\"numbers\">{0}</span>", i));
            }
            string lined = string.Join("<br />", l.ToArray());
            string css1= string.Empty;
            string css2 = string.Empty;
            if (inlineCss)
            {
                css1 = lineNumberCss;
                css2 = lineContentCss;
            }
            return string.Format(@"
            <div class=""linenumber""{0}>
                <pre>{1}</pre>
            </div>
            <div class=""linecontent""{2}>
                <pre>{3}</pre>
            </div>", css1, lined,css2, html);
        }

        /// <summary>
        /// Parses source code.
        /// </summary>
        /// <param name="source">The source code which will be parsed.</param>
        /// <param name="scannerResult">The result returned by the scanners after scanning the source code.</param>
        /// <returns>The highlighted source code.</returns>
        public override string Parse(string source, OccurrenceCollection scannerResult)
        {
            StringBuilder htmlWriter = new StringBuilder();

            int lastIndex = 0;

            for (int i = 0; i < scannerResult.Count; i++)
            {
                if ((scannerResult[i].Start - lastIndex) >= 0)
                {
                    if (scannerResult[i].Start > 0)
                    {
                        // Encode non-highlighted text first.
                        htmlWriter.Append(Helper.WriteEncodedText(source.Substring(lastIndex, scannerResult[i].Start - lastIndex)));
                    }

                    htmlWriter.Append(this.ParseToken(source.Substring(scannerResult[i].Start, scannerResult[i].Length), scannerResult[i].Node));
                }

                lastIndex = scannerResult[i].Start + scannerResult[i].Length;
            }

            // Encode the last bit of nonhighlighted text.
            if (lastIndex < source.Length)
            {
                htmlWriter.Append(Helper.WriteEncodedText(source.Substring(lastIndex)));
            }

            return htmlWriter.ToString();
        }

        /// <summary>
        /// Parses a token.
        /// </summary>
        /// <param name="token">The token which the node matched.</param>
        /// <param name="node">The node which matched the token.</param>
        /// <returns>The highlighted token.</returns>
        protected override string ParseToken(string token, INode node)
        {
            token = HttpUtility.HtmlEncode(token);
            string style = this.GetStyle(node);

            if (String.IsNullOrEmpty(node.NavigateUrl))
            {
                return String.Format("<span style=\"{0}\">{1}</span>", style, token);
            }

            return String.Format("<a href=\"{2}\" style=\"{0}\">{1}</a>", style, token, String.Format(node.NavigateUrl, token));
        }

        private static string ToHtmlColor(Color color)
        {
            return ColorTranslator.ToHtml(color);
        }

        private string GetStyle(INode node)
        {
            if (node.BackColor != Color.Transparent)
                return String.Format("background-color:{0}; color:{1}", HtmlParser.ToHtmlColor(node.BackColor), ColorTranslator.ToHtml(node.ForeColor));

            return String.Format("color:{0}", HtmlParser.ToHtmlColor(node.ForeColor));
        }

        #endregion Methods
    }
}